"""
    计算  SSE SC CH三个评估指标
    绘制三个指标和超参数之前的曲线
"""

# 1.导包
import os
os.environ["OMP_NUM_THREADS"]="4"

from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans                      # KMeans算法
from matplotlib import pyplot as plt
from sklearn.metrics import silhouette_score            # sc指标
from sklearn.metrics import calinski_harabasz_score     # ch指标


# 2.数据准备
x,y = make_blobs(
    n_samples=1000,
    n_features=4,
    centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
    cluster_std=[0.4, 0.2, 0.2, 0.2],
    random_state=929
)



# 3.模型训练
# 3.1 分别计算三个评估指标
def sse():
    value_list = []
    for i in range(1, 101):
        model = KMeans(n_clusters=i)

        # 获得预测值
        y_pre = model.fit_predict(x)

        # 获得sse评价指标
        sse = model.inertia_
        value_list.append(sse)

    # 3- 绘制肘方法的图形：横轴是n_clusters超参数；纵轴是评价指标
    plt.figure(figsize=(20, 20), dpi=150)
    plt.plot(range(1, 101), value_list, c="pink")
    plt.ylabel("SSE")
    plt.xticks(range(0, 101, 2))
    plt.grid()
    plt.show()


def sc():
    """
        ValueError: Number of labels is 1. Valid values are 2 to n_samples - 1 (inclusive)
        报错原因：SC指标至少需要两个簇，也就是至少要聚类为2个类别。根本原因是SC的计算公式要计算不同簇之间的距离
        解决办法：n_clusters至少从2开始
    """
    value_list = []
    for i in range(2, 101):
        model = KMeans(n_clusters=i)

        # 获得预测值
        y_pre = model.fit_predict(x)

        # 获得sc评价指标
        sc = silhouette_score(x, y_pre)
        value_list.append(sc)

    # 3- 绘制肘方法的图形：横轴是n_clusters超参数；纵轴是评价指标
    plt.figure(figsize=(20, 20), dpi=150)
    plt.plot(range(2, 101), value_list, c="pink")
    plt.ylabel("SC")
    plt.xticks(range(0, 101, 2))
    plt.grid()
    plt.show()


def ch():
    """
        ValueError: Number of labels is 1. Valid values are 2 to n_samples - 1 (inclusive)
        报错原因：SC指标至少需要两个簇，也就是至少要聚类为2个类别。根本原因是SC的计算公式要计算不同簇之间的距离
        解决办法：n_clusters至少从2开始
    """
    value_list = []
    for i in range(2, 101):
        model = KMeans(n_clusters=i)

        # 获得预测值
        y_pre = model.fit_predict(x)

        # 获得sc评价指标
        ch = calinski_harabasz_score(x, y_pre)
        value_list.append(ch)

    # 3- 绘制肘方法的图形：横轴是n_clusters超参数；纵轴是评价指标
    plt.figure(figsize=(20, 20), dpi=150)
    plt.plot(range(2, 101), value_list, c="r")
    plt.ylabel("CH")
    plt.xticks(range(0, 101, 2))
    plt.grid()
    plt.show()

def all(type):
    value_list = []

    start = 2
    if type == "SSE":
        start = 1

    for i in range(start, 101):
        # 2.1- 模型训练
        model = KMeans(n_clusters=i)
        y_predict = model.fit_predict(x)

        # 2.2- 获得评价指标
        if type == "SSE":
            # SSE指标
            value_list.append(model.inertia_)
        elif type == "CH":
            # CH轮廓系数指标
            value_list.append(calinski_harabasz_score(x, y_predict))
        else:
            # SC指标
            value_list.append(silhouette_score(x, y_predict))

    # 3- 绘制肘方法的图形：横轴是n_clusters超参数；纵轴是评价指标
    plt.figure(figsize=(20, 20), dpi=150)
    plt.plot(range(start, 101), value_list, c="r")
    plt.ylabel(type)
    plt.xticks(range(0, 101, 2))
    plt.grid()
    plt.show()


if __name__ == '__main__':
    # sse()
    # sc()
    # ch()
    all("SSE")